<template>
  <div class="drag-container">
    <div class="btn-group-right">
      <button v-if="!readOnly " @click="description"><span class="btn-description">备注</span></button>
      <button v-if="!readOnly " @click="save"><span class="btn-save">保存</span></button>
    </div>

    <div @drop.capture.prevent="onDrop($event)" @dragover.prevent>
      <step-node v-for="(node,index) in nodes" :ref="node.ref" :id="node.id" :index="index"
                 @remove="removeNode(index)" :key="node.id"></step-node>
    </div>
    <edit-modal id="editModal" ref="editModal"></edit-modal>
  </div>
</template>
<style scoped lang="scss">
  @import "../style/variables";
  .btn-group-right {
    position: absolute;
    top: 5px;
    right: 10px;
  }
  button {
    width: 80px;
    height: 35px;
    text-align: center;
    padding: 0;
    span {
      padding-left: 15px;
      display: block;
    }
  }
  .btn-description {
    background: url("../assets/steps/Edit.png") 10px 0 no-repeat;
  }
  .btn-save {
    background: url("../assets/steps/save.png") 10px 0 no-repeat;
  }
  .drag-container {
    background: $draw-background;
    height: 100%;
    width: inherit;
    > div{
      height: 100%;
    }
  }
</style>
<script>
  import store from "../store/store";
  import editModal from "./ModalView.vue";
  import "jsplumb";
  import {Steps} from "../model/DataModel";
  import has from "lodash/has"
  import StepList from "../components/steps/list/stepList";
  import HttpRequest from "../model/HttpRequset";


  /**
   * 生成节点规则：从event.dataTransfer内获取tree传递的type和name
   * 1，验证validator==9999
   * 2，根据对应的type获取
   * 3，Vuex store内添加一条数据
   * 4，Modald 打开时从store获取数据
   * */

  export default{
    store,
    mounted(){
      (function (id, vueInstance) {
        let connections = store.state.step.connections;
        jsPlumb.importDefaults({
          Endpoint: ["Dot", {radius: 2}],
          Container: id,
          HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2},
          Connector: "StateMachine",
          ConnectionOverlays: [
            ["Arrow", {location: 1, id: "arrow", length: 14, foldback: 0.8}],
            // ["Label", {id: "label", cssClass: "aLabel"}],
            ["Label", {id: "trueLabel", cssClass: "leaf true",}],
            ["Label", {id: "falseLabel", cssClass: "leaf false",}]
          ]
        });
        jsPlumb.registerConnectionType("basic", {anchor: "Continuous", connector: "StateMachine"});
        jsPlumb.batch(
          function () {
            //双击时取消连线
            jsPlumb.bind("dblclick", function (c) {
              vueInstance.$confirm('删除连接后，节点数据的引用关系会失效, 是否继续?', '确认删除', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
              }).then(() => {
                jsPlumb.detach(c);
                store.dispatch("removeConnection", c);
                vueInstance.$message({type: 'success', message: '删除成功!'});
              }).catch(() => {
                vueInstance.$message({type: 'info', message: '已取消删除'});
              });
            });

            //连接时添加标签并且更新信息
            jsPlumb.bind("connection", function (info) {
              updateConnection(info.connection);
            });

            //避免两个节点间有多条连线,或者两个节点互相连线
            jsPlumb.bind("beforeDrop", function ({connection: {sourceId, targetId}}) {
              let currentNodeConnection = connections[targetId + "||" + sourceId],
                reverseConnection = connections[sourceId + "||" + targetId];
              if (currentNodeConnection) {
                return false
              }
              else if (reverseConnection) {
                return false
              }
              return true;
            });
            //删除连接
            jsPlumb.bind("connectionDetached", function (info) {
              updateConnection(info.connection, true);
            });
          }
        );
        //更新链接信息
        function updateConnection(conn, remove) {
          let r = remove || false;
          /**
           * 非删除则添加一条connection到store
           * */
          if (!r) {
            store.dispatch("addConnection", conn);
          }
          else {
            store.dispatch("removeConnection", conn);
          }
        }

        jsPlumb.ready(() => {
          let reg = new RegExp("(^|&)id=([^&]*)(&|$)"), result = window.location.search.substr(1).match(reg);
          if (result) {
            vueInstance.$store.commit("setId", result[2])
            vueInstance.initialization(result[2]);
          }
        });

      })(this.$el.id, this)
    },
    props: {
      readOnly: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        /**
         * 参数规则：
         * name：为组件中文名;        *
         * type：为组件类别 ,同时也是编辑窗口组件名,参考src/components/steps/stepList.js下注册的子组件
         * x:拖拽点的X轴
         * y:拖拽点的Y轴
         * ref:子组件索引，使用 this.$refs.ref获取子组件，命名规则为type+index
         * nodes:[{id:"2",ref:"tableInput0",type:'TableInput',name:"2132", x: 200, y: 100}]
         */
        nodes: [],
        nodeTypes: [],
        typeCountObject: {},
      }
    },
    components: {editModal},
    watch: {
      nodes(newVal){
        let typeObject = {};
        newVal.forEach(el => {
          let elNumArray = typeObject[el.type];
          if (elNumArray && Array.isArray(elNumArray)) {
            elNumArray.push(el._num);
          } else {
            typeObject[el.type] = [el._num];
          }
        })
        this.typeCountObject = typeObject;
      }
    },
    methods: {
      description(){
        this.$prompt('请设置备注信息', '填写备注', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputValue: this.$store.state.step.description
        }).then(({value}) => {
          this.$store.commit("setDescription", value);
        });
      },
      save(){
        let that = this;
        this.$prompt('请设置转换名', '保存转换', {
          confirmButtonText: '保存',
          cancelButtonText: '取消',
          inputValue: this.$store.state.step.name,
          beforeClose: this.nameExistCheck,
        }).then(({value}) => {
          this.$store.commit("setName", value);
          HttpRequest.saveTransformation(that.$store.getters.kettleJson).then(
            response => {
              let data = response.data;
              if (data.result == "success") {
                //let id = data.id ? data.id : "";
                let id = data.id;
                if (id && id != "") {
                  that.$store.commit("setId", id);
                }
                that.$message({message: data.msg, type: 'success'});
              }else{
                that.$message({message: data.msg, type: 'error'});
              }
            }).catch(response => {
            that.$message.error(response.data.msg)
          });
        }).catch(() => {
          this.$message({type: 'info', message: '已取消保存'});
        });

      },
      nameExistCheck(action, instance, done){
        let name = instance.inputValue;
        if (name == "" && action === 'confirm') {
          this.$message({type: 'info', message: '转换名称不能为空'});
          return;
        }
        let id = this.$store.state.step.schemeId || "";
        if (action === 'confirm') {

          HttpRequest.nameExistCheck(name, id).then(
            response => {
              let data = response.data;
              if (data.nameExist === true) {
                instance.editorErrorMessage = "方案名称重复"
              } else {
                done();
              }
            }
          );
        } else {
          done();
        }
      },
      onDrop(event){
        let {validator} = JSON.parse(event.dataTransfer.getData('Text'));
        if (validator == 9999)
          this.addNodeFromTree(event);
      },
      addNodeFromTree({dataTransfer, offsetX: x, offsetY: y}){
        //随机生成一个不重复Id,避免ID以数字开头
        let id = "a" + jsPlumbUtil.uuid().replace(/-/g, ""),
          {name = "emptyName", type = "NullType"} = JSON.parse(dataTransfer.getData('Text')),
          nodeInfo = Steps[type]({id, name, x, y, type, _num: 1}), typeIndexArray = this.typeCountObject[type];

        /**
         * 自动命名*/
        if (typeIndexArray && typeIndexArray.length > 0) {
          typeIndexArray.forEach(el => {
            if (nodeInfo._num == el) {
              nodeInfo._num += 1
            }
          })
        }
        nodeInfo.name = name + "_" + nodeInfo._num;
        this.addNode(nodeInfo);
      },
      /**
       * 添加节点，生成一条记录添加到Vuex中,然后添加一条画板节点
       * */
      addNode(nodeInfo){
        let {id, name, type, x, y, _num} = nodeInfo;
        if (has(Steps, type)) {
          //生成原型数据
          if (StepList[type]) {
            //vuex提交数据
            this.$store.commit("addNode", nodeInfo);
            //画板提交数据
            this.nodes.push({_num, id, type, name, x: x - 25, y: y - 25, ref: type + _num});
          }
          else {
            this.$notify.error({title: '错误', message: "节点未注册!", duration: 2000, offset: 200});
          }
        } else {
          this.$notify.error({title: '错误', message: "节点type未定义!", duration: 2000, offset: 200});
        }
      },
      /**
       * 删除节点
       * 1 vuex删除节点
       * 2，画布删除节点
       * */
      removeNode(i){
        if (i < this.nodes.length) {
          let {name, id} = this.nodes[i];

          this.$confirm(`是否删除当前节点:${name}？`, '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.$store.commit("removeNodeById", id);
            this.nodes.splice(i, 1);
            this.$message({
              type: 'success', message: '删除成功!'
            });
          }).catch(() => {
            this.$message({type: 'info', message: '已取消删除'});
          });
        } else {
          this.$notify.error({title: '错误', message: `节点${i}不存在!`});
        }
      },
      /*根据ID获取服务器数据并且填充到界面内*/
      initialization(id){
        let that = this;
        HttpRequest.requestSavingStepsFromServer(id).then(response => {
          let {hops, steps, name,description} = response.data;
          //step列表不为空，则调用addNode方法添加节点
          if (steps && steps.length > 0) {
            steps.forEach(el => {
              that.addNode(el)
            });
            if (hops && hops.length > 0) {
              //触发下一次dom更新后连接div
              that.$nextTick(_ => {
                  hops.forEach(el => {
                    jsPlumb.connect({
                      source: el.from, target: el.to,
                      type: "basic",
                    });
                  })
                }
              )
            }
          }
            //添加方案名
            that.$store.commit('setName', name);
            //添加备注
            that.$store.commit('setDescription',description);

        }).catch(response => {
          that.$notify.error({
            title: '错误',
            message: `从服务器获取初始化数据错误 id:${id}, resp:${response}`,
            duration: 4000,
            offset: 200
          });
        })
      }
    }
  }

</script>
